package com.sync.utils.common.base.controller.impl;

import com.sync.utils.common.constant.HeaderConstants;
import com.sync.utils.common.base.controller.BaseController;
import com.sync.utils.framework.entity.AppInfo;
import com.sync.utils.framework.entity.UserInfo;
import com.sync.utils.common.exception.InvokeException;
import com.sync.utils.framework.mail.MailService;
import com.sync.utils.framework.redis.utils.MessageUtil;
import com.sync.utils.framework.redis.utils.RedisCache;
import com.sync.utils.common.utils.StringHelper;
import com.sync.utils.common.utils.TokenUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 业务处理器基类
 */

public class BaseControllerImpl implements BaseController {

    protected final static Logger logger = LoggerFactory.getLogger(BaseControllerImpl.class);

    @Value("${app.developer.cache_key}")
    protected String appInfoCacheKey;

    @Autowired
    protected MailService mailService;

    @Autowired
    protected RedisCache redisCache;

    @Autowired
    protected MessageUtil messageUtil;

    protected HttpServletRequest request;

    protected HttpServletResponse response;

    /**
     * spring ModelAttribute
     * 放置在方法上面：表示请求该类的每个Action前都会首先执行它，也可以将一些准备数据的操作放置在该方法里面
     */
    @ModelAttribute
    public void setBaseBizController(HttpServletRequest request, HttpServletResponse response){
        this.request=request;
        this.response=response;
    }

    @Override
    public HttpServletRequest getRequest() {
        return this.request;
    }

    @Override
    public HttpServletResponse getResponse() {
        return this.response;
    }

    @Override
    public String getStringParam(String paramName) {
        String result = request.getParameter(paramName);
        result = StringHelper.decodeHtml(result);
        return result;
    }

    @Override
    public String getStringParam(String paramName, String defaultValue) {
        String result = getStringParam(paramName);
        if(StringHelper.isEmpty(result)) {
            return defaultValue;
        }
        return result;
    }

    @Override
    public String requireStringParam(String paramName) {
        return requireStringParam(paramName, paramName + " is required.");
    }

    @Override
    public String requireStringParam(String paramName, String tips) {
        String result = getStringParam(paramName);
        if(StringHelper.isEmpty(result)) {
            throw new InvokeException(tips);
        }
        return result;
    }

    @Override
    public int getIntParam(String paramName) {
        return parseIntParam(paramName, 0);
    }

    @Override
    public int getIntParam(String paramName, int defaultValue) {
        return parseIntParam(paramName, defaultValue);
    }

    @Override
    public int requireIntParam(String paramName) {
        return requireIntParam(paramName, paramName + " is required.", paramName + " is not a number.");
    }

    private int requireIntParam(String paramName, String tipsEmpty, String tipsNaN) {
        String result = request.getParameter(paramName);
        if(StringHelper.isEmpty(result)) {
            throw new InvokeException(tipsEmpty);
        }
        int value;
        try{
            value = Integer.parseInt(result);
        } catch (Exception ex) {
            logger.error("参数`" + paramName + "`对应的值`" + result + "`不是数字，返回0", ex);
            throw new InvokeException("参数`" + paramName + "`对应的值`" + result + "`不是数字，返回0");
        }
        return value;
    }

    @Override
    public long getLongParam(String paramName) {
        return parseLongParam(paramName, 0);
    }

    @Override
    public long getLongParam(String paramName, long defaultValue) {
        return parseLongParam(paramName, defaultValue);
    }

    @Override
    public long requireLongParam(String paramName) {
        return requireLongParam(paramName, paramName + " is required.", paramName + " is not a number.");
    }

    private long requireLongParam(String paramName, String tipsEmpty, String tipsNaN) {
        String result = request.getParameter(paramName);
        if(StringHelper.isEmpty(result)) {
            throw new  InvokeException(tipsEmpty);
        }
        long value;
        try{
            value = Long.parseLong(result);
        } catch (Exception ex) {
            logger.error("参数`" + paramName + "`对应的值`" + result + "`不是数字，返回0", ex);
            throw new  InvokeException(tipsNaN);
        }
        return value;
    }

    @Override
    public double getDoubleParam(String paramName) {
        return parseDoubleParam(paramName, 0);
    }

    @Override
    public double getDoubleParam(String paramName, double defaultValue) {
        return parseDoubleParam(paramName, defaultValue);
    }

    @Override
    public double requireDoubleParam(String paramName) {
        return requireDoubleParam(paramName, paramName + " is required.", paramName + " is not a number.");
    }

    private double requireDoubleParam(String paramName, String tipsEmpty, String tipsNaN) {
        String result = request.getParameter(paramName);
        if(StringHelper.isEmpty(result)) {
            throw new  InvokeException(tipsEmpty);
        }
        double value;
        try{
            value = Double.parseDouble(result);
        } catch (Exception ex) {
            logger.error("参数`" + paramName + "`对应的值`" + result + "`不是数字，返回0", ex);
            throw new  InvokeException(tipsNaN);
        }
        return value;
    }

    /**
     * 对 request 的 get/setAttribute 进行一层包装
     */
    protected Object attr(String key) {
        return request.getAttribute(key);
    }

    protected void attr(String key, Object value) {
        request.setAttribute(key, value);
    }

    private int parseIntParam(String paramName, int defaultValue) {
        String result = request.getParameter(paramName);
        if(StringHelper.isEmpty(result)) {
            return defaultValue;
        }
        int value;
        try{
            value = Integer.parseInt(result);
        } catch (Exception ex) {
            value = 0;
            logger.error("参数`" + paramName + "`对应的值`" + result + "`不是数字，返回0", ex);
            throw new InvokeException("参数`" + paramName + "`对应的值`" + result + "`不是数字，返回0");
        }
        return value;
    }

    private long parseLongParam(String paramName, long defaultValue) {
        String result = request.getParameter(paramName);
        if(StringHelper.isEmpty(result)) {
            return defaultValue;
        }
        long value;
        try{
            value = Long.parseLong(result);
        } catch (Exception ex) {
            value = 0;
            logger.error("参数`" + paramName + "`对应的值`" + result + "`不是数字，返回0", ex);
            throw new InvokeException("参数`" + paramName + "`对应的值`" + result + "`不是数字，返回0");
        }
        return value;
    }

    private double parseDoubleParam(String paramName, double defaultValue) {
        String result = request.getParameter(paramName);
        if(StringHelper.isEmpty(result)) {
            return defaultValue;
        }
        double value;
        try{
            value = Double.parseDouble(result);
        } catch (Exception ex) {
            value = 0;
            logger.error("参数`" + paramName + "`对应的值`" + result + "`不是数字，返回0", ex);
            throw new InvokeException("参数`" + paramName + "`对应的值`" + result + "`不是数字，返回0");
        }
        return value;
    }

    /**
     * 将前台传递过来的日期格式的字符串，自动转化为Date类型
     */
    @Override
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(Date.class, new CustomDateEditor(
                new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"), true));
        binder.registerCustomEditor(Date.class, new CustomDateEditor(
                new SimpleDateFormat("yyyy-MM-dd"), true));
    }

    @Override
    public UserInfo getLoginUser() {
        String token = request.getHeader(HeaderConstants.X_TOKEN);
        return TokenUtils.getTokenUser(token);
    }

    @Override
    public AppInfo getAppInfo() {
        String token = request.getHeader(HeaderConstants.X_TOKEN);
        return TokenUtils.getTokenAppInfo(token);
    }


}
